package cn.ycc1.functionlibrary.streams;

/**
 * Creating Streams
 * @author ycc
 * @date 2025/3/7
 */
public class CreatingStreams {
    /**
     * Creating a Stream
     * You have already created many streams in this tutorial, all by calling the stream() method of the Collection interface.
     * This method is very convenient: creating streams in this way requires only two simple lines of code, and you can use this
     * stream to experiment with almost any feature of the Stream API.
     *
     * As you are going to see, there are many other ways to create streams on many objects. Knowing these ways enables you to
     * leverage the Stream API in many places in your application and to write more readable and maintainable code.
     *
     * Let us quickly browse through the ones that you are going to see in this tutorial before deep diving into each of them.
     *
     * The first set of patterns uses factory methods from the Stream interface. With them, you can create streams from the
     * following elements:
     *
     * a vararg argument;
     * a supplier;
     * a unary operator, that generates the next element from the previous one;
     * a builder.
     * You can even create an empty stream, which may be convenient in some circumstances.
     *
     * You already saw that you can create a stream on a collection. If what you have is only an iterator and not a fully
     * fledged collection, then there is a pattern for you: you can create a stream on an iterator. If you have an array,
     * then there is also a pattern to create a stream on the elements of an array.
     *
     * It does not stop here. Many patterns have also been added to well-known objects from the JDK. You can then create streams
     * from the following elements:
     *
     * the characters of a string;
     * the lines of a text file;
     * the elements created by splitting a string of characters with a regular expressions;
     * a random variable, that can create a stream of random numbers.
     * You can also create a stream with a builder pattern.
     */

    /**
     * Creating a Stream from a Collection or an Iterator
     * You already know that there is a stream() method available in the Collection interface. This is probably the most classic
     * way of creating streams.
     *
     * In some cases, you may need to create a stream on the content of a map. There is no stream() method in the Map interface,
     * so you cannot create such a stream directly. But you can access the content of a map through three collections:
     *
     * the set of the keys, with keySet()
     * the set of the key-value pairs, with entrySet()
     * the collection of the values, with values().
     * The right pattern to use is to get one of these collections and create a stream on it.
     *
     * The Stream API gives you a pattern to create a stream from a simple iterator. An iterator is a very simple object to
     * create, so it may be a very convenient way to create a stream on a nonstandard source of data. The pattern is the
     * following.
     */

    /**
     * Creating an Empty Stream
     * Let us begin with the simplest of these patterns: the creation of an empty stream. There is a factory method for that
     * in the Stream interface. You can use it in the following way.
     */

    /**
     * Creating a Stream from a Vararg or an Array
     * These first two patterns are very similar. The first one uses the of() factory method in the Stream interface.
     * The second one uses the stream() factory method of the Arrays factory class. And in fact, if you check the source of
     * the Stream.of() method, you will see that it calls Arrays.stream().
     */

    /**
     * Creating a Stream from a Supplier
     * There are two factory methods on the Stream interface for that.
     *
     * The first one is generate() that takes a supplier as an argument. Everytime a new element is needed, this supplier is
     * called.
     *
     * You can create such a stream with the following code, but don't do it!
     */

    /**
     * Creating a Stream from a UnaryOperator and a Seed
     * Using a supplier is great if you need to generate constant streams. If you need an infinite stream with varying values,
     * then you can use the iterate() pattern.
     *
     * This pattern works with a seed, which is the first generated element. Then it uses a UnaryOperator to generate the next
     * element of the stream by transforming the previous element.
     */

    /**
     * Creating a Stream from a Range of Numbers
     * It is easy to create a range of numbers with the previous pattern. But it is even easier with the specialized streams
     * of numbers and their range() factory methods.
     *
     * The range() method takes the initial value and the upper bound of the range, excluded. You can also include the upper
     * bound with the rangeClosed() method. Calling LongStream.range(0L, 10L) will simply generate a stream with all the longs
     * between 0 and 9.
     *
     * This range() method can also be used to iterate through the elements of an array. Here is how you can do that.
     */

    /**
     * Creating a Stream of Random Numbers
     * The Random class is used to create random series of numbers. Starting with Java SE 8, several methods have been added
     * to this class to create stream of random numbers of different types: int, long, and double.
     *
     * You can create an instance of Random providing a seed. This seed is a long parameter. The random numbers depends on
     * that seed. For a given seed you will always get the same sequence of numbers. This may be handy in many circumstances,
     * including the writing of tests. In that case, you can rely on a sequence of numbers that is known in advance.
     *
     * There are three methods to generate such a stream, all defined in the Random class: ints(), longs(), and doubles().
     *
     * Several overloads are available for all these methods, which accept the following arguments:
     *
     * the number of elements this stream will generate;
     * the upper and lower bounds of the random numbers generated.
     */

    /**
     * Creating a Stream from the Characters of a String
     * The String class saw the addition of a chars() method in Java SE 8. This method returns an IntStream that gives you the
     * characters of this string.
     *
     * Each character is given as a code point, an integer that may remind you of the ASCII codes. In some cases, you may need
     * to convert this integer to a string, just holding this character.
     *
     * You have two patterns to do that, depending on the version of the JDK you are using.
     *
     * Up to Java SE 10, you can use the following code.
     */

    /**
     * Creating a Stream from the Lines of a Text File
     * Being able to open a stream on a text file is a very powerful pattern.
     *
     * The Java I/O API has a pattern to read a single line from a text file: BufferedReader.readLine(). You can call this
     * method from a loop and read your entire text file line by line to process it.
     *
     * Being able to process these lines with the Stream API gives you a more readable and more maintainable code.
     *
     * There are several patterns to create such a stream.
     *
     * If you need to refactor an existing code based on the use of a buffered reader, then you can use the lines() method
     * defined on this object. If you are writing new code to process the content of your text file, then you can use the
     * factory method Files.lines(). This last method takes a Path as an argument and has an overloaded method that takes a
     * CharSet in case the file you are reading is not encoded in UTF-8.
     *
     * You may be aware that a file resource, as any I/O resource, should be closed when you do not need it anymore.
     * Since you are using this file resource through the Stream API, you may be wondering how you are going to handle that.
     *
     * Well the good news is that the Stream interface implements the AutoCloseable interface. A stream is itself a resource
     * that you can close in case you need. This was not really needed in all the in-memory examples that you saw, but when
     * dealing with I/O resources, it becomes mandatory.
     */

    /**
     * Creating a Stream from a Regular Expression
     * The last example of this series of patterns is a method added to the Pattern class to create a stream on the elements
     * generated by the application of a regular expression to a string of characters.
     *
     * Suppose you need to split a string on a given separator. You have two patterns to do that.
     *
     * You can call the String.split() method;
     * Or, you can use the Pattern.compile().split() pattern.
     * Both patterns give you an array of strings, containing the resulting elements of the splitting.
     */

    /**
     * Creating a Stream with the Builder Pattern
     * Creating a stream using this pattern is a two-step process. First, you add the elements your stream will be consuming
     * in the builder. Then you create the stream from this builder. Once your builder has been used to create your stream,
     * you cannot add more elements to it, nor you can use it again to build another stream. You will get an
     * IllegalStateException if you do that.
     */

    /**
     * Creating a Stream on an HTTP Source
     * The last pattern we cover in this tutorial is about analyzing the body of an HTTP response. You saw that you can create
     * a stream on the lines of a text file, you can do the same on the body of an HTTP response. This pattern is given by
     * the HTTP Client API, added to JDK 11.
     *
     * Here is how it works. We are going to use it on a text available online: The Tale of Two Cities, by Charles Dickens,
     * made available online by the Gutenberg Project here: https://www.gutenberg.org/files/98/98-0.txt
     *
     * The beginning of the text file gives you information about the text itself. The book starts on the line that contains
     * "A TALE OF TWO CITIES". The end of the file is the licence under which this file is distributed.
     */


}
